//
// SoapTrace.Net - A soap message monitoring utility. 
//
// Copyright (C) 2005 Matthew Ward
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Matthew Ward (mrward@users.sourceforge.net)

using NUnit.Framework;
using SoapTrace.Core.Communication;
using SoapTrace.Tests.Utils;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace SoapTrace.Tests.MessagePlayback
{
	/// <summary>
	/// Tests the <see cref="WebServiceClient"/> when 
	/// a soap request was successfully sent and a response 
	/// received.
	/// </summary>
	[ TestFixture ]
	public class SuccessfulReplayTestFixture : WebServiceClient
	{
		SoapRequest RequestReceived;
		SoapResponse ResponseReceived;
		ClientId RequestClientId;
		ClientId ResponseClientId;
		MockTcpSocket MockTcpSocket;
		
		/// <summary>
		/// Initialises the test fixture.
		/// </summary>
		[ TestFixtureSetUp ]
		public void Init( )
		{
			SoapResponse Response = CreateSoapResponse( GetResponseMessage( ) );
			
			SoapRequest Request = CreateSoapRequest( GetRequestMessage( ) );
			
			this.SoapRequestMessageSent += new SoapRequestMessageReceivedEventHandler( OnSoapRequestSent );
			this.SoapResponseMessageReceived += new SoapResponseMessageReceivedEventHandler( OnSoapResponseReceived );
			this.Connect( "200.1.1.1", 80 );
			this.Send( Request );
			Thread.Sleep( 100 );
			this.Shutdown( );
		}
		
		/// <summary>
		/// Cleans up after test.
		/// </summary>
		[ TestFixtureTearDown ]
		public void TearDown( )
		{
			Shutdown( );
		}
		
		/// <summary>
		/// Check we received the response message.
		/// </summary>
		[ Test ]
		public void ResponseMessage( )
		{
			Assert.AreEqual( GetResponseMessage( ), 
			    String.Concat( ResponseReceived.Header, ResponseReceived.Message ),
				"Unexpected response message." );
		}
		
		/// <summary>
		/// Check we received a request.
		/// </summary>
		[ Test ]
		public void RequestMessage( )
		{
			Assert.AreEqual( GetRequestMessage( ), 
			    String.Concat( RequestReceived.Header, RequestReceived.Message ),
				"Unexpected request message." );
		}		
		     
		/// <summary>
		/// The client ids should match.
		/// </summary>
		[ Test ]
		public void ClientIds( )
		{
			Assert.AreSame( RequestClientId, ResponseClientId, "Client ids should match." );
		}
		
		/// <summary>
		/// Checks that the source name has been set.
		/// </summary>
		[ Test ]
		public void RequestSource( )
		{
			Assert.AreEqual( MockTcpSocket.LocalEndPoint.ToString( ), 
			                RequestReceived.Source,
			                "Unexpected request source." );
		}
		
		/// <summary>
		/// Checks that the source name has been set.
		/// </summary>
		[ Test ]
		public void ResponseSource( )
		{
			Assert.AreEqual( MockTcpSocket.LocalEndPoint.ToString( ), 
			                ResponseReceived.Source,
			                "Unexpected response source." );
		}		
		
		/// <summary>
		/// Returns a mock tcp socket.
		/// </summary>
		protected override ISocket CreateSocket( AddressFamily addressFamily,
			SocketType socketType,
			ProtocolType protocolType )
		{
			MockTcpSocket = new MockTcpSocket( );
			MockTcpSocket.SetReadBytes( UnicodeEncoding.UTF8.GetBytes( GetResponseMessage( ) ) );
			return MockTcpSocket;
		}
		
		/// <summary>
		/// Returns a fake host entry object.
		/// </summary>
		protected override IPHostEntry ResolveAddress( string address )
		{
			IPHostEntry Entry = new IPHostEntry( );
			
			IPAddress IPAddress = IPAddress.Parse( "200.1.1.1" );
			IPAddress[ ] AddressList = new IPAddress[ ] { IPAddress };
			
			Entry.AddressList = AddressList;
			
			return Entry;
		}		
		
		void OnSoapRequestSent( object source, SoapRequestReceivedEventArgs e )
		{
			RequestReceived = e.Request;	
			RequestClientId = e.ClientId;
		}
		
		void OnSoapResponseReceived( object source, SoapResponseReceivedEventArgs e )
		{
			ResponseReceived = e.Response;
			ResponseClientId = e.ClientId;
		}
		
		/// <summary>
		/// Creates a soap request object.
		/// </summary>
		SoapRequest CreateSoapRequest( string message )
		{
			SoapRequest Request = new SoapRequest( );
			
			AddMessage( Request, message );
			
			return Request;
		}
		
		/// <summary>
		/// Creates a soap response object.
		/// </summary>
		SoapResponse CreateSoapResponse( string message )
		{
			SoapResponse Response = new SoapResponse( );
			
			AddMessage( Response, message );			
			
			return Response;
		}		
		
		/// <summary>
		/// Adds the message text to a soap message object.
		/// </summary>
		/// <param name="message">A soap message object.</param>
		/// <param name="messageText">The message text.</param>
		void AddMessage( SoapMessage message, string messageText )
		{
			byte[ ] Bytes = UnicodeEncoding.UTF8.GetBytes( messageText );
			
			foreach( byte CurrentByte in Bytes )
			{
				message.AddByte( CurrentByte );
			}
		}
		
		/// <summary>
		/// Gets the soap request text.
		/// </summary>
		string GetRequestMessage( )
		{
			return "POST /webservices/latest.asmx HTTP/1.1\r\n" +
				"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 1.1.4322.573)\r\n" +
				"Content-Type: text/xml; charset=utf-8\r\n" +
				"SOAPAction: \"http://codeproject.com/webservices/GetMaxCommentListLength\"\r\n" +
				"Content-Length: 317\r\n" +
				"Expect: 100-continue\r\n" +
				"Connection: Keep-Alive\r\n" +
				"Host: www.codeproject.com\r\n" +
				"\r\n" +
				"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
				"<soap:Body><GetMaxCommentListLength xmlns=\"http://codeproject.com/webservices/\" /></soap:Body>" +
				"</soap:Envelope>";
		}
		
		/// <summary>
		/// Gets the expected soap response text.
		/// </summary>
		string GetResponseMessage( )
		{
			return "HTTP/1.1 200 OK\r\n" +
				"Server: Microsoft-IIS/5.0\r\n" +
				"Date: Mon, 31 Jan 2005 18:43:11 GMT\r\n" +
				"X-Powered-By: ASP.NET\r\n" +
				"X-AspNet-Version: 1.1.4322\r\n" +
				"Cache-Control: no-cache\r\n" +
				"Pragma: no-cache\r\n" +
				"Expires: -1\r\n" +
				"Content-Type: text/xml; charset=utf-8\r\n" +
				"Content-Length: 422\r\n" +
				"\r\n" +
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
				"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
				"<soap:Body><GetMaxCommentListLengthResponse xmlns=\"http://codeproject.com/webservices/\">" + 
				"<GetMaxCommentListLengthResult>10</GetMaxCommentListLengthResult>" +
				"</GetMaxCommentListLengthResponse>" +
				"</soap:Body>" +
				"</soap:Envelope>";
		}
	}
}
